import React, { memo, useState } from "react";
import { Button, Input } from "antd";
import http from "utils/http";
//import streamSaver from "streamsaver";
import { asyncPool } from "utils";

const SIZE = 100 * 1024 * 1024; //设置切片的大小

export default memo(function Down() {
  const [name, setname] = useState("");

  //获取文件大小
  const filesize = async (name) => {
    let res = await http.get(`/size/${name}`);
    return res.data;
  };

  //根据传入的参数发起范围请求
  const getBinaryContent = async (start, end, i) => {
    let result = await http.get(`down/${name}`, {
      headers: { Range: `bytes=${start}-${end}` },
      responseType: "blob",
    });
    return { index: i, data: result };
  };

  //合并buffer
  // const concatenate = (arrays) => {
  //   if (!arrays.length) return null;
  //   let totalLength = arrays.reduce((acc, value) => acc + value.length, 0);
  //   let result = new Uint8Array(totalLength);
  //   let length = 0;
  //   for (let array of arrays) {
  //     result.set(array, length);
  //     length += array.length;
  //   }
  //   return result;
  // };

  //保存文件
  const saveAs = ( name, buffers, mime = "application/octet-stream" ) => {
    const blob = new Blob([buffers], { type: mime });
    const blobUrl = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.download = name
    a.href = blobUrl;
    a.click();
    URL.revokeObjectURL(blob);
  };

  //下载文件
  const downfile = async () => {
    let contentLength = await filesize(name);
    let chunks = Math.ceil(contentLength / SIZE);
    let chunksl = [...new Array(chunks).keys()];

    //用流的方式操作不行   但是如果后端把文件变成压缩包  每个分片都是一个压缩包 应该就可以 此种方法 对内存的开销最小
    /* for (let i of chunksl) {
      let start = i * SIZE;
      let end = i + 1 === chunks ? contentLength : (i + 1) * SIZE - 1;
      let res = await getBinaryContent(start, end, i);
      let fileStream = streamSaver.createWriteStream(name,{flags:'a',start});
      if (res.stream.stream().pipeTo) {
        await res.stream.stream().pipeTo(fileStream);
      }
    } */

    let results = await asyncPool(3,chunksl,(i)=>{
      let start = i * SIZE;
      let end = i + 1 === chunks ? contentLength : (i + 1) * SIZE - 1;
      return getBinaryContent(start, end, i);
    }) 
    results.sort((a,b)=>a.index - b.index)
    //这种方法文件过大 会造成阵列缓冲区分配失败 buffer 也不行
    /* const sortedBuffers = results.map((item) => new Uint8Array(item.buffer));
    let buffers = concatenate(sortedBuffers); */
    let arr = results.map(r=>r.data)
    let buffers = new Blob(arr)
    saveAs(name,buffers)
  };
  return (
    <div>
      <Input
        placeholder="请输入文件名"
        onChange={(e) => setname(e.target.value)}
      />
      <Button type="primary" onClick={downfile}>
        下载
      </Button>
    </div>
  );
});
